﻿using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using RestSharp;
using System.IO;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Text.RegularExpressions;
using System.Linq;
using System.IO.IsolatedStorage;
using System.Threading;
using System.Windows.Threading;


namespace Strava1
{
    public class MainViewModel : INotifyPropertyChanged
    {
        public MainViewModel()
        {
            Rides = new ObservableCollection<Ride>();
            RidesCVS = new CollectionViewSource();
            RidesCVS.Source = Segments;
            RidesCVS.SortDescriptions.Add(new SortDescription("Detail.StartDate", ListSortDirection.Descending));

            Segments = new ObservableCollection<Segment>();
            SegmentsCVS = new CollectionViewSource();
            SegmentsCVS.Source = Segments;
            SegmentsCVS.SortDescriptions.Add(new SortDescription("TopPlacing", ListSortDirection.Ascending));
            SegmentsCVS.SortDescriptions.Add(new SortDescription("PlacingCount", ListSortDirection.Descending));
            SegmentsCVS.SortDescriptions.Add(new SortDescription("MyRelativePower", ListSortDirection.Descending));

            Alerts = new ObservableCollection<Alert>();
            AlertsCVS = new CollectionViewSource();
            AlertsCVS.Source = Alerts;
            AlertsCVS.SortDescriptions.Add(new SortDescription("FoundDateTime", ListSortDirection.Descending));

            MapObjects = new ObservableCollection<MapPolylineObj>();

            wcRides = new WebClient();
            wcRides.OpenReadCompleted += new OpenReadCompletedEventHandler(wcRides_OpenReadCompleted);

            wcSegmentExplorer = new WebClient();
            wcSegmentExplorer.OpenReadCompleted += new OpenReadCompletedEventHandler(wcSegmentExplorer_OpenReadCompleted);

            wcSegmentExplorerDetail = new WebClient();
            wcSegmentExplorerDetail.OpenReadCompleted += new OpenReadCompletedEventHandler(wcSegmentExplorerDetail_OpenReadCompleted);
            ExplorerSegments = new ObservableCollection<Segment>();

            cacheTimer = new DispatcherTimer();
            cacheTimer.Interval = new TimeSpan(0, 0, 0, 1);
            cacheTimer.Tick += new EventHandler(cacheTimer_Tick);
        }


        /// <summary>
        /// A collection for ItemViewModel objects.
        /// </summary>
        public ObservableCollection<Ride> Rides { get; private set; }
        public CollectionViewSource RidesCVS { get; set; }

        public ObservableCollection<Segment> Segments { get; set; }
        public CollectionViewSource SegmentsCVS { get; set; }

        public ObservableCollection<Athlete> Follows { get; set; }

        public ObservableCollection<Alert> Alerts { get; set; }
        public CollectionViewSource AlertsCVS { get; set; }

        public ObservableCollection<Athlete> AllAthletes = new ObservableCollection<Athlete>();
        public ObservableCollection<Effort> AllEfforts = new ObservableCollection<Effort>();
        public ObservableCollection<MapPoint> AllMapPoints = new ObservableCollection<MapPoint>();

        public ObservableCollection<MapPolylineObj> MapObjects { get; set; }

        private DispatcherTimer cacheTimer;

        WebClient wcRides;
        WebClient wcRideDetail;
        WebClient wcRideEfforts;
        WebClient wcRideMap;
        WebClient wcElevation;
        WebClient wcSegmentDetails;
        WebClient wcSegmentEfforts;
        WebClient wcSegmentMyEfforts;
        WebClient wcEffort;
        WebClient wcSegmentExplorer;
        WebClient wcSegmentExplorerDetail;
        public string ServiceLocation = "app.strava.com/api"; //"192.168.33.187";
        public Athlete me;

        public string LoadType { get; set; }
        public int NewCourseCount { get; set; }
        public List<string> SegmentPlacingChangesList { get; set; }
        public List<string> NewSegmentList { get; set; }
        //public List<int> SegmentExplorerList { get; set; }
        public int SegmentExplorerItemsRemaining = 0;

        public ObservableCollection<Segment> ExplorerSegments { get; set; }

        List<int> wcRideDetailsArr = new List<int>();
        int wcRideDetailsActive = 0;
        List<int> wcRideEffortsArr = new List<int>();
        int wcRideEffortsActive = 0;
        List<int> wcRideMapArr = new List<int>();
        int wcRideMapActive = 0;
        public List<string> wcElevationArr = new List<string>();
        int wcElevationActive = 0;
        List<int> wcSegmentDetailsArr = new List<int>();
        int wcSegmentDetailsActive = 0;
        List<int> wcSegmentEffortsArr = new List<int>();
        int wcSegmentEffortsActive = 0;
        List<int> wcSegmentMyEffortsArr = new List<int>();
        int wcSegmentMyEffortsActive = 0;
        List<int> wcEffortArr = new List<int>();
        int wcEffortActive = 0;

        private int _segFirstCount;
        public int SegFirstCount
        {
            get
            {
                return _segFirstCount;
            }
            set
            {
                if (value != _segFirstCount)
                {
                    _segFirstCount = value;
                    NotifyPropertyChanged("SegFirstCount");
                }
            }
        }
        private int _segSecondCount;
        public int SegSecondCount
        {
            get
            {
                return _segSecondCount;
            }
            set
            {
                if (value != _segSecondCount)
                {
                    _segSecondCount = value;
                    NotifyPropertyChanged("SegSecondCount");
                }
            }
        }
        private int _segThirdCount;
        public int SegThirdCount
        {
            get
            {
                return _segThirdCount;
            }
            set
            {
                if (value != _segThirdCount)
                {
                    _segThirdCount = value;
                    NotifyPropertyChanged("SegThirdCount");
                }
            }
        }
        private int _segOtherCount;
        public int SegOtherCount
        {
            get
            {
                return _segOtherCount;
            }
            set
            {
                if (value != _segOtherCount)
                {
                    _segOtherCount = value;
                    NotifyPropertyChanged("SegOtherCount");
                }
            }
        }

        private bool _busy = false;
        public bool Busy
        {
            get
            {
                return _busy;
            }
            set
            {
                if (value != _busy)
                {
                    _busy = value;
                    NotifyPropertyChanged("Busy");
                }
            }
        }

        private string _busyMessage = "";
        public string BusyMessage
        {
            get
            {
                return _busyMessage;
            }
            set
            {
                if (value != _busyMessage)
                {
                    _busyMessage = value;
                    NotifyPropertyChanged("BusyMessage");
                }
            }
        }

        private string _username = "name";
        public string Username
        {
            get
            {
                return _username;
            }
            set
            {
                if (value != _username)
                {
                    _username = value;
                    IsolatedStorageSettings.ApplicationSettings["username"] = value;
                    NotifyPropertyChanged("Username");
                }
            }
        }
        private string _email = "name@.co.com";
        public string Email
        {
            get
            {
                return _email;
            }
            set
            {
                if (value != _email)
                {
                    _email = value;
                    IsolatedStorageSettings.ApplicationSettings["email"] = value;
                    NotifyPropertyChanged("Email");
                }
            }
        }
        private string _password = "pwd";
        public string Password
        {
            get
            {
                return _password;
            }
            set
            {
                if (value != _password)
                {
                    _password = value;
                    IsolatedStorageSettings.ApplicationSettings["password"] = value;
                    NotifyPropertyChanged("Password");
                }
            }
        }
        private string _token = "token";
        public string Token
        {
            get
            {
                return _token;
            }
            set
            {
                if (value != _token)
                {
                    _token = value;
                    IsolatedStorageSettings.ApplicationSettings["token"] = value;
                    NotifyPropertyChanged("Token");
                }
            }
        }
        private int _userId = 0;
        public int UserId
        {
            get
            {
                return _userId;
            }
            set
            {
                if (value != _userId)
                {
                    _userId = value;
                    IsolatedStorageSettings.ApplicationSettings["userId"] = value;
                    NotifyPropertyChanged("UserId");
                }
            }
        }

        private DateTime _lastTopCheck;
        public DateTime LastTopCheck
        {
            get
            {
                return _lastTopCheck;
            }
            set
            {
                if (value != _lastTopCheck)
                {
                    _lastTopCheck = value;
                    IsolatedStorageSettings.ApplicationSettings["lastTopCheck"] = value;
                    NotifyPropertyChanged("LastTopCheck");
                }
            }
        }
        private DateTime _lastFullCheck;
        public DateTime LastFullCheck
        {
            get
            {
                return _lastFullCheck;
            }
            set
            {
                if (value != _lastFullCheck)
                {
                    _lastFullCheck = value;
                    IsolatedStorageSettings.ApplicationSettings["lastFullCheck"] = value;
                    NotifyPropertyChanged("LastFullCheck");
                }
            }
        }
        private int _itemsRemaining = 10;
        public int ItemsRemaining
        {
            get
            {
                return _itemsRemaining;
            }
            set
            {
                if (_itemsRemaining != value)
                {
                    _itemsRemaining = value;
                    NotifyPropertyChanged("ItemsRemaining");
                }
            }
        }
        void SetItemsRemaining()
        {
            ItemsRemaining = wcRideDetailsArr.Count + wcRideEffortsArr.Count + wcSegmentDetailsArr.Count + wcSegmentEffortsArr.Count + wcSegmentMyEffortsArr.Count + wcRideMapArr.Count + wcElevationArr.Count + SegmentExplorerItemsRemaining;
            if (ItemsRemaining > 0)
            {
                Busy = true;
                BusyMessage = "getting data (" + ItemsRemaining.ToString() + ")";
            }
            else
            {
                Busy = false;

            }
        }

        private string _sampleProperty = "Sample Runtime Property Value";
        /// <summary>
        /// Sample ViewModel property; this property is used in the view to display its value using a Binding
        /// </summary>
        /// <returns></returns>
        public string SampleProperty
        {
            get
            {
                return _sampleProperty;
            }
            set
            {
                if (value != _sampleProperty)
                {
                    _sampleProperty = value;
                    NotifyPropertyChanged("SampleProperty");
                }
            }
        }

        public bool IsDataLoaded
        {
            get;
            private set;
        }

        /// <summary>
        /// Creates and adds a few ItemViewModel objects into the Items collection.
        /// </summary>
        public void LoadData()
        {
            Busy = true;
            BusyMessage = "getting data";
            LoadType = "Full";
            Rides = new ObservableCollection<Ride>();
            Segments = new ObservableCollection<Segment>();
            Uri uri = new Uri("http://" + ServiceLocation + "/v1/rides?athleteName=" + Username + "&startDate=2010-01-01&endDate=2011-01-01");  //&startDate=2012-01-01
            wcRides.OpenReadAsync(uri);
        }

        void wcRides_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            ProcessRequest(e, "Rides");
        }

        void wcRideDetails_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            ProcessRequest(e, "RideDetail");
        }

        void wcRideEfforts_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            ProcessRequest(e, "RideEfforts");
        }

        void wcRideMap_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            ProcessRequest(e, "RideMap");
        }

        void wcElevation_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            ProcessRequest(e, "Elevation");
        }

        void wcSegmentDetails_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            ProcessRequest(e, "SegmentDetail");
        }

        void wcSegmentEfforts_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            ProcessRequest(e, "SegmentEfforts");
        }

        void wcSegmentMyEfforts_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            ProcessRequest(e, "SegmentMyEfforts");
        }

        void wcSegmentExplorer_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            ProcessRequest(e, "SegmentExplorer");
        }

        void wcSegmentExplorerDetail_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            ProcessRequest(e, "SegmentExplorerDetail");
        }

        void ProcessRequest(OpenReadCompletedEventArgs e, string type)
        {
            if (e.Error != null)
            {
                Busy = false;
                Console.WriteLine("failure" + type);
                //Failure(e.Error.Message);
            }

            else
            {
                using (var ms = e.Result)
                {
                    String streamStr;
                    MemoryStream stream;

                    switch (type)
                    {
                        case "Rides":
                            using (StreamReader reader = new StreamReader(ms))
                            {
                                streamStr = StripOuterObject(reader.ReadLine());
                                stream = new MemoryStream(Encoding.UTF8.GetBytes(streamStr));
                            }
                            var rides = new DataContractJsonSerializer(typeof(ObservableCollection<Ride>));

                            ObservableCollection<Ride> localRides = (ObservableCollection<Ride>)rides.ReadObject(stream);

                            foreach (Ride ride in localRides)
                            {
                                if ((LoadType != "NewCourses") ||
                                    (Rides.FirstOrDefault(r => r.Id == ride.Id) == null))
                                {
                                    NewCourseCount++;
                                    ride.IsDirty = true;
                                    Rides.Add(ride);
                                    wcRideDetailsArr.Add(ride.Id);
                                    wcRideEffortsArr.Add(ride.Id);
                                    wcRideMapArr.Add(ride.Id);
                                    SetItemsRemaining();

                                    GetNextRideDetails();
                                }
                            }
                            break;

                        case "RideDetail":
                            using (StreamReader reader = new StreamReader(ms))
                            {
                                streamStr = StripOuterObject(reader.ReadLine());
                                stream = new MemoryStream(Encoding.UTF8.GetBytes(streamStr));
                            }
                            var rideDetail = new DataContractJsonSerializer(typeof(RideDetail));
                            RideDetail rd = (RideDetail)rideDetail.ReadObject(stream);

                            Rides.First(s => s.Id == rd.Id).Detail = rd;

                            wcRideDetailsActive--;
                            GetNextRideDetails();

                            //RidesCVS.View.Refresh();
                            break;

                        case "RideMap":
                            var rideMap = new DataContractJsonSerializer(typeof(RideMap));
                            RideMap rm = (RideMap)rideMap.ReadObject(ms);

                            Ride mapRide = Rides.First(s => s.Id == rm.RideId);
                            mapRide.MapLocations = rm.MapLocations;

                            int counter1 = -1;
                            int counter2 = 0;
                            mapRide.latlngstr = new List<string>();
                            mapRide.MapPointLists = new List<List<MapPoint>>();

                            foreach (MapPoint mp in rm.MapLocations)
                            {
                                if (counter2 % 50 == 0)
                                {
                                    counter1++;
                                    mapRide.latlngstr.Add("");
                                    mapRide.MapPointLists.Add(new List<MapPoint>());
                                }
                                mapRide.latlngstr[counter1] += mp.Lat + "," + mp.Lng + "|";
                                counter2++;
                            }

                            for (int i = 0; i < mapRide.latlngstr.Count; i++)
                            {
                                mapRide.latlngstr[i] = mapRide.latlngstr[i].TrimEnd('|');
                            }

                            SaveCache(mapRide.MapLocations, "rideMap-" + mapRide.Id.ToString());

                            wcRideMapActive--;
                            GetNextRideMap();

                            break;

                        case "Elevation":
                            string streamStr2;
                            using (StreamReader reader = new StreamReader(ms))
                            {
                                streamStr = "";
                                while (!reader.EndOfStream)
                                {
                                    streamStr += reader.ReadLine();
                                }
                                streamStr2 = StripOuterObject(streamStr);
                                stream = new MemoryStream(Encoding.UTF8.GetBytes(streamStr2));
                            }
                            if (streamStr2 == "[]")
                            {
                                MessageBox.Show(streamStr);
                                wcElevationArr = new List<string>();
                            }

                            var eleRltSer = new DataContractJsonSerializer(typeof(ObservableCollection<ElevationResult>));
                            ObservableCollection<ElevationResult> elevationResults = (ObservableCollection<ElevationResult>)eleRltSer.ReadObject(stream);

                            List<MapPoint> mapLocations = new List<MapPoint>();
                            string latlngstr2 = "";
                            foreach (ElevationResult er in elevationResults)
                            {
                                MapPoint mp = new MapPoint();
                                mp.Elv = er.Elevation;
                                mp.Lat = er.Location.Lat;
                                mp.Lng = er.Location.Lng;
                                mapLocations.Add(mp);
                                latlngstr2 += mp.Lat + "," + mp.Lng + "|";
                            }
                            latlngstr2 = latlngstr2.TrimEnd('|');

                            Ride elvMapRide = (from r in Rides
                                               where r.latlngstr != null
                                               from s in r.latlngstr
                                               where s == latlngstr2
                                               select r).FirstOrDefault();

                            if (elvMapRide != null)
                            {
                                int counter3 = 0;
                                foreach (string lls in elvMapRide.latlngstr)
                                {
                                    if (lls == latlngstr2)
                                    {
                                        if (elvMapRide.MapPointLists[counter3] == null)
                                        {
                                            elvMapRide.MapPointLists[counter3] = new List<MapPoint>();
                                        }
                                        elvMapRide.MapPointLists[counter3] = mapLocations;
                                        elvMapRide.SetMapLocations();
                                        break;
                                    }
                                    counter3++;
                                }

                                if (wcElevationArr.Count == 0)
                                {
                                    SaveCache(elvMapRide.MapLocations, "rideMap-" + elvMapRide.Id.ToString());
                                    elvMapRide.NotifyPropertyChanged("Locations");
                                    elvMapRide.NotifyPropertyChanged("ProfilePathObjects");
                                    elvMapRide.NotifyPropertyChanged("ElevationLineData");
                                }
                            }

                            wcElevationActive--;
                            GetNextElevation();

                            break;

                        case "RideEfforts":
                            var rideEfforts = new DataContractJsonSerializer(typeof(RideEfforts));
                            RideEfforts eff = (RideEfforts)rideEfforts.ReadObject(ms);

                            Ride effortsRide = Rides.First(s => s.Id == eff.RideId);

                            effortsRide.IsEffortsDirty = true;

                            effortsRide.Efforts = new ObservableCollection<Effort>();

                            effortsRide.EffortsCount = eff.EffortSegments.Count;

                            foreach (EffortSegment effortSegment in eff.EffortSegments)
                            {
                                if (effortSegment.Segment.ClimbCategory != "0")
                                {
                                }

                                effortSegment.Effort.SegmentId = effortSegment.Segment.Id;

                                Segment segmentExists = DoesSegmentExist(effortSegment.Segment.Id);

                                if (segmentExists != null)
                                {
                                    effortSegment.Segment = segmentExists;

                                    // still need to get effort data as it has probably changed
                                    if (!wcSegmentEffortsArr.Contains(effortSegment.Segment.Id))
                                    {
                                        wcSegmentEffortsArr.Add(effortSegment.Segment.Id);
                                        wcSegmentMyEffortsArr.Add(effortSegment.Segment.Id);
                                    }
                                }
                                else
                                {
                                    //effortSegment.Segment = effortSegment.Segment;
                                    effortSegment.Segment.IsDirty = true;
                                    Segments.Add(effortSegment.Segment);
                                    effortSegment.Segment.Distance = effortSegment.Effort.Distance;

                                    if (!wcSegmentEffortsArr.Contains(effortSegment.Segment.Id))
                                    {
                                        wcSegmentEffortsArr.Add(effortSegment.Segment.Id);
                                        wcSegmentMyEffortsArr.Add(effortSegment.Segment.Id);
                                    }

                                    if (LoadType == "NewPlacings")
                                    {
                                        NewSegmentList.Add("New segment \"" + effortSegment.Segment.Name + "\" added|Segment|" + effortSegment.Segment.Id);
                                    }

                                    SetItemsRemaining();
                                }

                                effortSegment.Effort.Segment = effortSegment.Segment;
                                //effortSegment.Effort.Ride = effortsRide;
                                effortsRide.Efforts.Add(effortSegment.Effort);
                                AllEfforts.Add(effortSegment.Effort);
                            }


                            //SaveCache(effortsRide.Efforts, "rideEfforts-" + effortsRide.Id.ToString());

                            wcRideEffortsActive--;
                            GetNextRideEfforts();

                            break;

                        case "SegmentEfforts":
                            var segmentEfforts = new DataContractJsonSerializer(typeof(SegmentEfforts));
                            SegmentEfforts se = (SegmentEfforts)segmentEfforts.ReadObject(ms);

                            if (se.Segment != null)
                            {
                                Segment segmentExists2 = DoesSegmentExist(se.Segment.Id);

                                // due to weird bug make sure there are no duplicates
                                List<int> athletes = new List<int>();
                                List<Effort> effortsToRemove = new List<Effort>();
                                foreach (Effort effort in se.EffortsList)
                                {
                                    if (athletes.Contains(effort.Athlete.Id))
                                    {
                                        effortsToRemove.Add(effort);
                                    }
                                    else
                                    {
                                        //calc speed
                                        effort.Athlete = DoesAthleteExist(effort.Athlete);
                                        effort.AverageSpeed = 2.23693629F * segmentExists2.Distance / float.Parse(effort.ElapsedTime.ToString());
                                    }
                                    athletes.Add(effort.Athlete.Id);

                                    effort.SegmentId = segmentExists2.Id;
                                }

                                foreach (Effort effort in effortsToRemove)
                                {
                                    se.EffortsList.Remove(effort);
                                }

                                for (int i = 1; i <= se.EffortsList.Count; i++)
                                {
                                    se.EffortsList[i - 1].OverallPlacing = i;
                                }

                                int currentPlacing = 0;
                                int newPlacing = 0;

                                currentPlacing = segmentExists2.TopPlacing;
                                newPlacing = (from eff5 in se.EffortsList
                                              where eff5.Athlete.Username == Username.ToLower()
                                              select eff5.OverallPlacing).FirstOrDefault();
                                if (newPlacing == 0)
                                {
                                    newPlacing = 51;
                                }

                                if (currentPlacing != newPlacing)
                                {
                                    segmentExists2.TopPlacing = newPlacing;
                                    segmentExists2.Efforts = se.EffortsList;
                                    segmentExists2.PlacingCount = se.EffortsList.Count();
                                    segmentExists2.PopulateTimeDifference();

                                    segmentExists2.IsEffortsDirty = true;

                                    if (currentPlacing == 0)
                                    {
                                        SegmentPlacingChangesList.Add("New segment \"" + se.Segment.Name + "\" P" + newPlacing.ToString() + "|Segment|" + se.Segment.Id);
                                    }
                                    else
                                    {
                                        SegmentPlacingChangesList.Add("You have moved from position " + currentPlacing.ToString() + " to position " + newPlacing.ToString() + " on segment \"" + se.Segment.Name + "\"|Segment|" + se.Segment.Id);
                                    }

                                    //SaveCache(segmentExists2.Efforts, "segmentEfforts-" + segmentExists2.Id.ToString());
                                }
                            }
                            wcSegmentEffortsActive--;
                            GetNextSegmentEfforts();

                            break;

                        case "SegmentMyEfforts":
                            var segmentMyEfforts = new DataContractJsonSerializer(typeof(SegmentEfforts));
                            SegmentEfforts myse = (SegmentEfforts)segmentMyEfforts.ReadObject(ms);

                            //myse.EffortsList.OrderBy(

                            Segment segmentExists3 = DoesSegmentExist(myse.Segment.Id);

                            int placing = 1;
                            foreach (Effort effort in from eff6 in myse.EffortsList
                                                      orderby eff6.ElapsedTime
                                                      select eff6)
                            {
                                effort.OverallPlacing = placing;
                                placing++;
                                effort.SegmentId = segmentExists3.Id;
                                effort.AverageSpeed = 2.23693629F * segmentExists3.Distance / float.Parse(effort.ElapsedTime.ToString());
                            }

                            segmentExists3.MyEfforts = myse.EffortsList;
                            segmentExists3.IsMyEffortsDirty = true;

                            //SaveCache(segmentExists3.MyEfforts, "segmentMyEfforts-" + segmentExists3.Id.ToString());

                            wcSegmentMyEffortsActive--;
                            GetNextSegmentMyEfforts();

                            break;

                        case "SegmentExplorer":
                            using (StreamReader reader = new StreamReader(ms))
                            {
                                streamStr = StripOuterObject(reader.ReadLine());
                                stream = new MemoryStream(Encoding.UTF8.GetBytes(streamStr));
                            }
                            var SESer = new DataContractJsonSerializer(typeof(ObservableCollection<Segment>));
                            ExplorerSegments = (ObservableCollection<Segment>)SESer.ReadObject(stream);

                            string uriStr = "http://" + ServiceLocation + "/v3/segments/details?ids=";

                            foreach (Segment segment in ExplorerSegments)
                            {
                                uriStr += segment.Id + ",";
                            }

                            Uri uri = new Uri(uriStr.TrimEnd(','));

                            if (!wcSegmentExplorerDetail.IsBusy)
                            {
                                wcSegmentExplorerDetail.OpenReadAsync(uri);
                            }

                            //http://app.strava.com/api/v3/segments/details?ids=1059483%2C946644

                            //SegmentExplorerItemsRemaining--;
                            break;

                        case "SegmentExplorerDetail":
                            using (StreamReader reader = new StreamReader(ms))
                            {
                                streamStr = StripOuterObject(reader.ReadLine());
                                stream = new MemoryStream(Encoding.UTF8.GetBytes(streamStr));
                            }
                            var SEDSer = new DataContractJsonSerializer(typeof(ObservableCollection<SegmentExplorerDetail>));
                            ObservableCollection<SegmentExplorerDetail> SEDSegments = (ObservableCollection<SegmentExplorerDetail>)SEDSer.ReadObject(stream);

                            foreach (SegmentExplorerDetail sed in SEDSegments)
                            {
                                Segment segment = ExplorerSegments.FirstOrDefault(s => s.Id == sed.Id);
                                if ((segment != null) && (sed.Points != null))
                                {
                                    Collection<double> points = decodePolyline(sed.Points);

                                    segment.MapLocations = new ObservableCollection<MapPoint>();

                                    for (int i = 0; i < points.Count; i++)
                                    {
                                        MapPoint mp = new MapPoint();
                                        mp.Lat = float.Parse(points[i].ToString());
                                        i++;
                                        mp.Lng = float.Parse(points[i].ToString());
                                        segment.MapLocations.Add(mp);
                                    }
                                }
                            }

                            //SegmentExplorerItemsRemaining--;
                            break;
                    }
                }
            }

            if (cacheTimer.IsEnabled)
            {
                cacheTimer.Stop();
            }
            cacheTimer.Start();
        }

        public Segment DoesSegmentExist(int id)
        {
            Segment segment = (from s in Segments
                               where s.Id == id
                               select s).FirstOrDefault();

            return segment;
        }

        public Athlete DoesAthleteExist(Athlete athlete)
        {
            Athlete foundAthlete = (from a in AllAthletes
                                    where a.Id == athlete.Id
                                    select a).FirstOrDefault();

            if (foundAthlete != null)
            {
                return foundAthlete;
            }
            AllAthletes.Add(athlete);
            return athlete;
        }

        private object LoadFromCache(string name, Type type)
        {
            IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
            IsolatedStorageFileStream fileStream;

            if (myIsolatedStorage.FileExists(name + ".txt"))
            {
                fileStream = myIsolatedStorage.OpenFile(name + ".txt", FileMode.Open, FileAccess.Read);
                string streamStr = "";
                using (StreamReader reader = new StreamReader(fileStream))
                {
                    streamStr = reader.ReadLine();
                }
                /* var serializer = new DataContractJsonSerializer(type);
                 MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(streamStr));
                 object obj = new ObservableCollection<Ride>();
                 Rides = (ObservableCollection<Ride>)serializer.ReadObject(stream);*/
            }
            return new object();
        }

        private void GetNextRideDetails()
        {
            if (wcRideDetailsActive < 20)
            {
                if (wcRideDetailsArr.Count() > 0)
                {
                    wcRideDetailsActive++;
                    wcRideDetail = new WebClient();
                    wcRideDetail.OpenReadCompleted += new OpenReadCompletedEventHandler(wcRideDetails_OpenReadCompleted);
                    Uri rideDetailsUri = new Uri("http://" + ServiceLocation + "/v1/rides/" + wcRideDetailsArr[0]);
                    wcRideDetail.OpenReadAsync(rideDetailsUri);

                    wcRideDetailsArr.RemoveAt(0);
                    SetItemsRemaining();
                    GetNextRideDetails();
                }
                else
                {
                    GetNextRideEfforts();
                }
            }

        }
        private void GetNextRideEfforts()
        {
            if (wcRideEffortsActive < 20)
            {
                if (wcRideEffortsArr.Count() > 0)
                {
                    wcRideEffortsActive++;
                    wcRideEfforts = new WebClient();
                    wcRideEfforts.OpenReadCompleted += new OpenReadCompletedEventHandler(wcRideEfforts_OpenReadCompleted);
                    Uri rideEffortsUri = new Uri("http://" + ServiceLocation + "/v2/rides/" + wcRideEffortsArr[0] + "/efforts");
                    wcRideEfforts.OpenReadAsync(rideEffortsUri);

                    wcRideEffortsArr.RemoveAt(0);
                    SetItemsRemaining();
                    GetNextRideEfforts();
                }
                else
                {
                    GetNextRideMap();
                }
            }
        }

        private void GetNextRideMap()
        {
            if (wcRideMapActive < 20)
            {
                if (wcRideMapArr.Count() > 0)
                {
                    wcRideMapActive++;
                    wcRideMap = new WebClient();
                    wcRideMap.OpenReadCompleted += new OpenReadCompletedEventHandler(wcRideMap_OpenReadCompleted);
                    Uri rideMapUri = new Uri("http://" + ServiceLocation + "/v2/rides/" + wcRideMapArr[0] + "/map_details?token=" + Token);
                    wcRideMap.OpenReadAsync(rideMapUri);

                    wcRideMapArr.RemoveAt(0);
                    SetItemsRemaining();
                    GetNextRideMap();
                }
                else
                {
                    GetNextSegmentEfforts();
                    //GetNextElevation();
                }
            }
        }
        public void GetNextElevation()
        {
            if (wcElevationActive < 2)
            {
                if (wcElevationArr.Count() > 0)
                {
                    wcElevationActive++;
                    wcElevation = new WebClient();
                    wcElevation.OpenReadCompleted += new OpenReadCompletedEventHandler(wcElevation_OpenReadCompleted);
                    Uri elevationUri = new Uri("http://maps.googleapis.com/maps/api/elevation/json?sensor=false&locations=" + wcElevationArr[0]);
                    wcElevation.OpenReadAsync(elevationUri);

                    wcElevationArr.RemoveAt(0);
                    SetItemsRemaining();
                    GetNextElevation();
                }
                /*else
                {
                    GetNextSegmentEfforts();
                }*/
            }
        }

        /*private void GetNextSegmentDetails()
        {
            if ((wcRideEffortsArr.Count() == 0) && 
                (wcSegmentDetailsActive < 5))
            {
                if (wcSegmentDetailsArr.Count() > 0)
                {
                    wcSegmentDetailsActive++;
                    wcSegmentDetails = new WebClient();
                    wcSegmentDetails.OpenReadCompleted += new OpenReadCompletedEventHandler(wcSegmentDetails_OpenReadCompleted);
                    Uri SegmentDetailsUri = new Uri("http://" + ServiceLocation + "/v1/segments/" + wcSegmentDetailsArr[0]);
                    wcSegmentDetails.OpenReadAsync(SegmentDetailsUri);

                    wcSegmentDetailsArr.RemoveAt(0);
                    SetItemsRemaining();
                }
            }
        }*/
        private void GetNextSegmentEfforts()
        {
            if ((wcRideEffortsArr.Count == 0) &&
                (wcSegmentEffortsActive < 20))
            {
                if (wcSegmentEffortsArr.Count() > 0)
                {
                    wcSegmentEffortsActive++;
                    wcSegmentEfforts = new WebClient();
                    wcSegmentEfforts.OpenReadCompleted += new OpenReadCompletedEventHandler(wcSegmentEfforts_OpenReadCompleted);
                    Uri SegmentEffortsUri = new Uri("http://" + ServiceLocation + "/v1/segments/" + wcSegmentEffortsArr[0] + "/efforts?best=true");
                    wcSegmentEfforts.OpenReadAsync(SegmentEffortsUri);

                    wcSegmentEffortsArr.RemoveAt(0);
                    SetItemsRemaining();
                    GetNextSegmentEfforts();
                }
                else
                {
                    if (LoadType == "SegmentPlacings")
                    {
                        SaveCache(Rides, "srides-" + Username.ToLower());
                        SaveCache(Segments, "segments-" + Username.ToLower());
                        SegmentsCVS.View.Refresh();
                        SetSegmentPlacings();
                    }
                    else
                    {
                        GetNextSegmentMyEfforts();
                    }
                }
            }
        }
        private void GetNextSegmentMyEfforts()
        {
            if ((wcRideEffortsArr.Count == 0) &&
                (wcSegmentMyEffortsActive < 20))
            {
                if (wcSegmentMyEffortsArr.Count() > 0)
                {
                    wcSegmentMyEffortsActive++;
                    wcSegmentMyEfforts = new WebClient();
                    wcSegmentMyEfforts.OpenReadCompleted += new OpenReadCompletedEventHandler(wcSegmentMyEfforts_OpenReadCompleted);
                    Uri SegmentMyEffortsUri = new Uri("http://" + ServiceLocation + "/v1/segments/" + wcSegmentMyEffortsArr[0] + "/efforts?athleteId=" + UserId.ToString());
                    wcSegmentMyEfforts.OpenReadAsync(SegmentMyEffortsUri);

                    wcSegmentMyEffortsArr.RemoveAt(0);
                    SetItemsRemaining();
                    GetNextSegmentMyEfforts();
                }
            }
        }


        private string StripOuterObject(string json, bool stripArray = false)
        {
            json = Regex.Replace(json, @"^[^:]*:", "");
            json = json.Remove(json.Length - 1);

            json = json.Trim();

            if ((json.Substring(0, 1) == "[") &&
                (json.Substring(json.Length - 1) != "]"))
            {
                json = Regex.Replace(json, @"\][^\]]*$", "]");
            }

            return json;
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private void Failure(string errorMessage)
        {
            //App.ViewModel.Busy = false;
            MessageBox.Show(errorMessage);
            //Logout();
        }



        private bool IsRideFullyLoaded(Ride ride)
        {
            if ((ride.Detail == null) ||
                (ride.Efforts == null))
            {
                return false;
            }

            if (ride.Efforts.Count(e => e.Segment == null) > 0)
            {
                return false;
            }

            foreach (Effort effort in ride.Efforts)
            {
                if ((effort.Segment == null) ||
                    (effort.Segment.Efforts == null) ||
                    (effort.Segment.MyEfforts == null))
                {
                    return false;
                }
            }

            return true;
        }

        public void LoadCache()
        {
            Busy = true;
            BusyMessage = "loading from cache";

            //username
            if (IsolatedStorageSettings.ApplicationSettings.Contains("username"))
            {
                Username = (string)IsolatedStorageSettings.ApplicationSettings["username"];
            }
            if (IsolatedStorageSettings.ApplicationSettings.Contains("userId"))
            {
                UserId = (int)IsolatedStorageSettings.ApplicationSettings["userId"];
            }
            if (IsolatedStorageSettings.ApplicationSettings.Contains("email"))
            {
                Email = (string)IsolatedStorageSettings.ApplicationSettings["email"];
            }
            if (IsolatedStorageSettings.ApplicationSettings.Contains("password"))
            {
                Password = (string)IsolatedStorageSettings.ApplicationSettings["password"];
            }
            if (IsolatedStorageSettings.ApplicationSettings.Contains("token"))
            {
                Token = (string)IsolatedStorageSettings.ApplicationSettings["token"];
            }
            if (IsolatedStorageSettings.ApplicationSettings.Contains("lastTopCheck"))
            {
                LastTopCheck = (DateTime)IsolatedStorageSettings.ApplicationSettings["lastTopCheck"];
            }
            if (IsolatedStorageSettings.ApplicationSettings.Contains("lastFullCheck"))
            {
                LastFullCheck = (DateTime)IsolatedStorageSettings.ApplicationSettings["lastFullCheck"];
            }

            me = new Athlete();
            me.Username = Username;
            me.Id = UserId;
            me.Name = "name";
            AllAthletes.Add(me);
            //
            IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
            IsolatedStorageFileStream fileStream;

            if (myIsolatedStorage.FileExists("rides-" + Username.ToLower() + ".txt"))
            {
                fileStream = myIsolatedStorage.OpenFile("rides-" + Username.ToLower() + ".txt", FileMode.Open, FileAccess.Read);
                string streamStr = "";
                using (StreamReader reader = new StreamReader(fileStream))
                {
                    streamStr = reader.ReadLine();
                }
                var serializer = new DataContractJsonSerializer(typeof(ObservableCollection<Ride>));
                MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(streamStr));
                Rides = new ObservableCollection<Ride>();
                Rides = (ObservableCollection<Ride>)serializer.ReadObject(stream);
            }

            if (myIsolatedStorage.FileExists("segments-" + Username.ToLower() + ".txt"))
            {
                fileStream = myIsolatedStorage.OpenFile("segments-" + Username.ToLower() + ".txt", FileMode.Open, FileAccess.Read);
                string streamStr = "";
                using (StreamReader reader = new StreamReader(fileStream))
                {
                    streamStr = reader.ReadLine();
                }
                var serializer = new DataContractJsonSerializer(typeof(ObservableCollection<Segment>));
                MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(streamStr));
                Segments = new ObservableCollection<Segment>();
                Segments = (ObservableCollection<Segment>)serializer.ReadObject(stream);
            }

            /*if (myIsolatedStorage.FileExists("athletes-" + Username.ToLower() + ".txt"))
            {
                fileStream = myIsolatedStorage.OpenFile("athletes-" + Username.ToLower() + ".txt", FileMode.Open, FileAccess.Read);
                string streamStr = "";
                using (StreamReader reader = new StreamReader(fileStream))
                {
                    streamStr = reader.ReadLine();
                }
                var serializer = new DataContractJsonSerializer(typeof(ObservableCollection<Alert>));
                MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(streamStr));
                AllAthletes = new ObservableCollection<Athlete>();
                AllAthletes = (ObservableCollection<Athlete>)serializer.ReadObject(stream);
            }*/

            if (myIsolatedStorage.FileExists("alerts-" + Username.ToLower() + ".txt"))
            {
                fileStream = myIsolatedStorage.OpenFile("alerts-" + Username.ToLower() + ".txt", FileMode.Open, FileAccess.Read);
                string streamStr = "";
                using (StreamReader reader = new StreamReader(fileStream))
                {
                    streamStr = reader.ReadLine();
                }
                var serializer = new DataContractJsonSerializer(typeof(ObservableCollection<Alert>));
                MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(streamStr));
                Alerts = new ObservableCollection<Alert>();
                Alerts = (ObservableCollection<Alert>)serializer.ReadObject(stream);
            }

            foreach (Ride ride in Rides)
            {
                ride.FullDetailsLoaded = IsRideFullyLoaded(ride);
            }

            if (App.Current.RootVisual != null)
            {
                ((FrameworkElement)App.Current.RootVisual).DataContext = this;
            }
            RidesCVS.Source = Rides;
            RidesCVS.View.MoveCurrentToPosition(-1);
            RidesCVS.View.Refresh();
            SegmentsCVS.Source = Segments;
            SegmentsCVS.View.MoveCurrentToPosition(-1);
            SegmentsCVS.View.Refresh();
            AlertsCVS.Source = Alerts;
            AlertsCVS.View.MoveCurrentToPosition(-1);
            AlertsCVS.View.Refresh();

            SetSegmentPlacings();

            IsDataLoaded = true;

            Busy = false;
        }


        public void SaveCache(object ObjectToCache, string Name)
        {
            MemoryStream ms = new MemoryStream();
            if (Name.IndexOf("rides-") == 0)
            {
                var serializer = new DataContractJsonSerializer(typeof(ObservableCollection<Ride>));
                serializer.WriteObject(ms, (ObservableCollection<Ride>)ObjectToCache);
            }
            if (Name.IndexOf("rideMap-") == 0)
            {
                var serializer = new DataContractJsonSerializer(typeof(ObservableCollection<MapPoint>));
                serializer.WriteObject(ms, (ObservableCollection<MapPoint>)ObjectToCache);
            }
            if (Name.IndexOf("rideEfforts-") == 0)
            {
                var serializer = new DataContractJsonSerializer(typeof(ObservableCollection<Effort>));
                serializer.WriteObject(ms, (ObservableCollection<Effort>)ObjectToCache);
            }
            if (Name.IndexOf("rideProfilePathObjects-") == 0)
            {
                var serializer = new DataContractJsonSerializer(typeof(ObservableCollection<PathGeometryObj>));
                serializer.WriteObject(ms, (ObservableCollection<PathGeometryObj>)ObjectToCache);
            }
            if (Name.IndexOf("segments-") == 0)
            {
                var serializer = new DataContractJsonSerializer(typeof(ObservableCollection<Segment>));
                serializer.WriteObject(ms, (ObservableCollection<Segment>)ObjectToCache);
            }
            if ((Name.IndexOf("segmentEfforts-") == 0) ||
                (Name.IndexOf("segmentMyEfforts-") == 0))
            {
                var serializer = new DataContractJsonSerializer(typeof(ObservableCollection<Effort>));
                serializer.WriteObject(ms, (ObservableCollection<Effort>)ObjectToCache);
            }
            if (Name.IndexOf("athletes-") == 0)
            {
                var serializer = new DataContractJsonSerializer(typeof(ObservableCollection<Athlete>));
                serializer.WriteObject(ms, (ObservableCollection<Athlete>)ObjectToCache);
            }
            if (Name.IndexOf("alerts-") == 0)
            {
                var serializer = new DataContractJsonSerializer(typeof(ObservableCollection<Alert>));
                serializer.WriteObject(ms, (ObservableCollection<Alert>)ObjectToCache);
            }

            string streamStr = "";
            ms.Position = 0;
            using (StreamReader reader = new StreamReader(ms))
            {
                streamStr = reader.ReadLine();
                //stream = new MemoryStream(Encoding.UTF8.GetBytes(streamStr));
            }

            //return retVal;

            IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
            IsolatedStorageFileStream fileStream;
            //Open existing file
            if (myIsolatedStorage.FileExists(Name + ".txt"))
            {
                myIsolatedStorage.DeleteFile(Name + ".txt");
            }
            fileStream = new IsolatedStorageFileStream(Name + ".txt", FileMode.Create, FileAccess.Write, myIsolatedStorage);

            using (StreamWriter writer = new StreamWriter(fileStream))
            {
                writer.Write(streamStr);
                writer.Close();
            }
            fileStream.Dispose();
        }

        void cacheTimer_Tick(object sender, EventArgs e)
        {
            SetItemsRemaining();

            if (ItemsRemaining == 0)
            {
                cacheTimer.Stop();

                if (LoadType == "SegmentExplorer")
                {
                    NotifyPropertyChanged("ExplorerSegments");
                    foreach (Segment segment in ExplorerSegments)
                    {
                        segment.NotifyPropertyChanged("Locations");
                    }
                }
                else
                {
                    Busy = true;
                    BusyMessage = "saving cache...";
                    string messageStr = "";

                    /*foreach (Ride ride in Rides)
                    {
                        ride.CalculatePositions("MyResults");
                    }*/

                    foreach (Ride ride in Rides.Where(r => r.IsEffortsDirty))
                    {
                        SaveCache(ride.Efforts, "rideEfforts-" + ride.Id.ToString());
                        ride.IsEffortsDirty = false;
                    }

                    foreach (Ride ride in Rides.Where(r => r.Efforts == null && r.EffortsCount > 0))
                    {
                        ride.PopulateEfforts();
                    }

                    foreach (Segment segment in Segments.Where(s => s.IsEffortsDirty))
                    {
                        SaveCache(segment.Efforts, "segmentEfforts-" + segment.Id.ToString());
                        segment.IsEffortsDirty = false;
                    }
                    foreach (Segment segment in Segments.Where(s => s.IsMyEffortsDirty))
                    {
                        foreach (Ride ride in from r in Rides
                                              where r.Efforts != null
                                              from eff in r.Efforts
                                              where eff.SegmentId == segment.Id
                                              select r)
                        {
                            ride.CalculatePositions("Overall");
                            ride.CalculatePositions("MyResults");
                            ride.IsDirty = true;
                        }
                        SaveCache(segment.MyEfforts, "segmentMyEfforts-" + segment.Id.ToString());
                        segment.IsMyEffortsDirty = false;
                    }

                    LastFullCheck = DateTime.Now;

                    if (LoadType == "NewCourses")
                    {
                        switch (NewCourseCount)
                        {
                            case 0:
                                messageStr += "No new courses added.";
                                break;
                            case 1:
                                messageStr += "1 new course added.";
                                break;
                            default:
                                messageStr += NewCourseCount.ToString() + " new courses added.";
                                break;
                        }
                        Alert alert = new Alert();
                        alert.FoundDateTime = DateTime.Now;
                        alert.Message = messageStr;
                        Alerts.Add(alert);
                        //MessageBox.Show(messageStr);
                    }
                    if ((LoadType == "SegmentPlacings") || (LoadType == "NewCourses"))
                    {
                        if (LoadType == "NewCourses")
                        {
                            messageStr += "\n\n";
                        }
                        switch (SegmentPlacingChangesList.Count)
                        {
                            case 0:
                                messageStr += "No changes to your segment placings.";
                                break;
                            case 1:
                                messageStr += "1 change to your segment placings:\n\n";
                                break;
                            default:
                                messageStr += SegmentPlacingChangesList.Count.ToString() + " changes to your segment placings:\n\n";
                                break;
                        }

                        SegmentPlacingChangesList.Reverse();

                        List<int> rideIds = new List<int>();

                        foreach (string str in SegmentPlacingChangesList)
                        {
                            Alert alert = new Alert();
                            alert.FoundDateTime = DateTime.Now;
                            string[] strArr = str.Split('|');
                            alert.Message = strArr[0];
                            alert.Type = strArr[1];
                            alert.Id = int.Parse(strArr[2]);
                            Alerts.Add(alert);

                            messageStr += strArr[0] + "\n\n";

                            if (alert.Type == "Segment")
                            {
                                foreach (Ride ride in from r in Rides
                                                      where r.Efforts != null
                                                      from eff in r.Efforts
                                                      where eff.SegmentId == alert.Id
                                                      select r)
                                {
                                    if (!rideIds.Contains(ride.Id))
                                    {
                                        ride.CalculatePositions("Overall");
                                        ride.CalculatePositions("MyResults");

                                        rideIds.Add(ride.Id);
                                    }
                                }
                            }
                        }

                        // MessageBox.Show(messageStr);
                    }
                    if (LoadType == "NewPlacings")
                    {
                        switch (NewSegmentList.Count)
                        {
                            case 0:
                                messageStr += "No new segments.";
                                break;
                            case 1:
                                messageStr += "1 new segment:\n\n";
                                break;
                            default:
                                messageStr += NewSegmentList.Count.ToString() + " new segments:\n\n";
                                break;
                        }
                        foreach (string str in NewSegmentList)
                        {
                            Alert alert = new Alert();
                            alert.FoundDateTime = DateTime.Now;
                            string[] strArr = str.Split('|');
                            alert.Message = strArr[0];
                            alert.Type = strArr[1];
                            alert.Id = int.Parse(strArr[2]);
                            Alerts.Add(alert);

                            messageStr += strArr[0] + "\n\n";
                        }

                        //MessageBox.Show(messageStr);
                    }
                    LoadType = "";

                    if (Rides.Count(r => r.IsDirty) > 0)
                    {
                        SaveCache(Rides, "rides-" + Username.ToLower());
                        foreach (Ride ride in from r in Rides
                                              where r.IsDirty
                                              select r)
                        {
                            ride.IsDirty = false;
                        }
                    }
                    if (Segments.Count(s => s.IsDirty) > 0)
                    {
                        SaveCache(Segments, "segments-" + Username.ToLower());
                        foreach (Segment segment in from s in Segments
                                                    where s.IsDirty
                                                    select s)
                        {
                            segment.IsDirty = false;
                        }
                    }
                    SaveCache(AllAthletes, "athletes-" + Username.ToLower());
                    SaveCache(Alerts, "alerts-" + Username.ToLower());

                    SegmentsCVS.View.Refresh();
                    RidesCVS.View.Refresh();

                    SetSegmentPlacings();

                    Busy = false;

                    if (messageStr != "")
                    {
                        MessageBox.Show(messageStr);
                    }
                }
                //MessageBox.Show("data cached");
            }
        }

        private void SetSegmentPlacings()
        {
            SegFirstCount = 0;
            SegSecondCount = 0;
            SegThirdCount = 0;
            SegOtherCount = 0;

            foreach (Segment segment in Segments)
            {
                switch (segment.TopPlacing)
                {
                    case 1:
                        SegFirstCount++;
                        break;
                    case 2:
                        SegSecondCount++;
                        break;
                    case 3:
                        SegThirdCount++;
                        break;
                    default:
                        SegOtherCount++;
                        break;
                }
            }
        }

        internal void ClearCache()
        {
            IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
            foreach (string filename in myIsolatedStorage.GetFileNames())
            {
                if (filename.IndexOf("alerts-") < 0)
                {
                    myIsolatedStorage.DeleteFile(filename);
                }
            }

            IsolatedStorageSettings.ApplicationSettings.Clear();
            IsolatedStorageSettings.ApplicationSettings["username"] = "username";
            IsolatedStorageSettings.ApplicationSettings["userId"] = 0;
            IsolatedStorageSettings.ApplicationSettings["email"] = "name@co.com";
            IsolatedStorageSettings.ApplicationSettings["password"] = "pwd";
            IsolatedStorageSettings.ApplicationSettings["token"] = "token";
            Rides = new ObservableCollection<Ride>();
            Segments = new ObservableCollection<Segment>();
            //Alerts = new ObservableCollection<Alert>();
            RidesCVS.Source = Rides;
            RidesCVS.View.Refresh();
            SegmentsCVS.Source = Segments;
            SegmentsCVS.View.Refresh();
            //AlertsCVS.Source = Alerts;
            //AlertsCVS.View.Refresh();
            SetSegmentPlacings();
        }

        public void CheckForChanges()
        {
            // check for new courses
            // check top 3 placings changes
            // check for new segments

            LastTopCheck = DateTime.Now;
        }

        internal void SetSegmentOrder(string header)
        {
            SegmentsCVS.SortDescriptions.Clear();

            switch (header)
            {
                case "placing":
                    SegmentsCVS.SortDescriptions.Add(new SortDescription("TopPlacing", ListSortDirection.Ascending));
                    SegmentsCVS.SortDescriptions.Add(new SortDescription("PlacingCount", ListSortDirection.Descending));
                    SegmentsCVS.SortDescriptions.Add(new SortDescription("MyRelativePower", ListSortDirection.Descending));
                    break;
                case "distance":
                    SegmentsCVS.SortDescriptions.Add(new SortDescription("Distance", ListSortDirection.Descending));
                    break;
                case "elevation":
                    SegmentsCVS.SortDescriptions.Add(new SortDescription("ElevationDifference", ListSortDirection.Descending));
                    break;
                case "gradient":
                    SegmentsCVS.SortDescriptions.Add(new SortDescription("AverageGrade", ListSortDirection.Descending));
                    break;
                case "climb category":
                    SegmentsCVS.SortDescriptions.Add(new SortDescription("ClimbCategoryOrder", ListSortDirection.Descending));
                    SegmentsCVS.SortDescriptions.Add(new SortDescription("ElevationDifference", ListSortDirection.Descending));
                    break;
                case "time behind":
                    SegmentsCVS.SortDescriptions.Add(new SortDescription("TimeDifferenceToBest", ListSortDirection.Ascending));
                    break;
                case "name":
                    SegmentsCVS.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
                    break;
                case "relative power":
                    SegmentsCVS.SortDescriptions.Add(new SortDescription("MyRelativePower", ListSortDirection.Descending));
                    break;
                case "VAM":
                    SegmentsCVS.SortDescriptions.Add(new SortDescription("MyVAM", ListSortDirection.Descending));
                    break;
            }

            SegmentsCVS.View.Refresh();
        }

        internal void SetRideOrder(string header)
        {
            RidesCVS.SortDescriptions.Clear();

            switch (header)
            {
                case "date":
                    RidesCVS.SortDescriptions.Add(new SortDescription("Detail.StartDate", ListSortDirection.Descending));
                    break;
                case "distance":
                    RidesCVS.SortDescriptions.Add(new SortDescription("Detail.Distance", ListSortDirection.Descending));
                    break;
                case "elevation":
                    RidesCVS.SortDescriptions.Add(new SortDescription("Detail.ElevationGain", ListSortDirection.Descending));
                    break;
                case "average speed":
                    RidesCVS.SortDescriptions.Add(new SortDescription("Detail.AverageSpeed", ListSortDirection.Descending));
                    break;
                case "name":
                    RidesCVS.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
                    break;
            }

            RidesCVS.View.Refresh();
        }

        internal void CheckForNewCourses()
        {
            /*foreach (Ride ride in from r in Rides
                                  where r.Efforts == null
                                  select r)
            {
                ride.PopulateEfforts();
            }*/

            SegmentPlacingChangesList = new List<string>();

            NewCourseCount = 0;
            LoadType = "NewCourses";
            Uri uri = new Uri("http://" + ServiceLocation + "/v1/rides?athleteName=" + Username);  //  + "&startDate=2010-01-01&endDate=2010-05-01"

            if (!wcRides.IsBusy)
            {
                wcRides.OpenReadAsync(uri);
            }
        }

        internal void CheckSegmentPlacings(string top = "")
        {
            Busy = true;

            foreach (Ride ride in Rides)
            {
                ride.PopulateEfforts();
            }
            LoadType = "SegmentPlacings";
            SegmentPlacingChangesList = new List<string>();
            foreach (Segment segment in Segments)
            {
                if ((top == "Top") ||
                    (segment.TopPlacing < 3))
                {
                    //segment.PopulateEfforts();
                    //segment.PopulateMyEfforts();
                    wcSegmentEffortsArr.Add(segment.Id);
                }
            }
            GetNextSegmentEfforts();

            /*SegmentsCVS.Source = Segments;
            SegmentsCVS.View.Refresh();*/
        }

        internal void CheckForNewSegments()
        {
            LoadType = "NewPlacings";
            NewSegmentList = new List<string>();

            foreach (Ride ride in Rides)
            {
                //ride.PopulateEfforts();
                wcRideEffortsArr.Add(ride.Id);
            }
            GetNextRideEfforts();

            //Uri uri = new Uri(App.ViewModel.ServiceName + "/v1/rides?athleteName=" + Username.ToLower());  //&startDate=2012-01-01
            //wcRides.OpenReadAsync(uri);
        }

        internal void ClearAlertsCache()
        {
            Alerts = new ObservableCollection<Alert>();
            AlertsCVS.Source = Alerts;
            AlertsCVS.View.Refresh();

            IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
            IsolatedStorageFileStream fileStream;

            if (myIsolatedStorage.FileExists(Username.ToLower() + ".txt"))
            {
                fileStream = myIsolatedStorage.OpenFile(Username.ToLower() + ".txt", FileMode.Open, FileAccess.ReadWrite);
                string streamStr = "";
                using (StreamReader reader = new StreamReader(fileStream))
                {    //Visualize the text data in a TextBlock text
                    streamStr = reader.ReadLine();
                }

                streamStr = Regex.Replace(streamStr, @"\|\|alerts-" + Username + @"\:\:.*$", "||alerts::");

                fileStream = new IsolatedStorageFileStream(Username.ToLower() + ".txt", FileMode.Create, FileAccess.Write, myIsolatedStorage);

                using (StreamWriter writer = new StreamWriter(fileStream))
                {
                    writer.Write(streamStr);
                    writer.Close();
                }

                fileStream.Dispose();
            }
        }

        public double DistanceBetween(MapPoint mp1, MapPoint mp2)
        {
            var Lat1 = mp1.Lat;
            var Long1 = mp1.Lng;
            var Lat2 = mp2.Lat;
            var Long2 = mp2.Lng;

            double dDistance = Double.MinValue;
            double dLat1InRad = Lat1 * (Math.PI / 180.0);
            double dLong1InRad = Long1 * (Math.PI / 180.0);
            double dLat2InRad = Lat2 * (Math.PI / 180.0);
            double dLong2InRad = Long2 * (Math.PI / 180.0);

            double dLongitude = dLong2InRad - dLong1InRad;
            double dLatitude = dLat2InRad - dLat1InRad;

            // Intermediate result a.
            double a = Math.Pow(Math.Sin(dLatitude / 2.0), 2.0) +
                       Math.Cos(dLat1InRad) * Math.Cos(dLat2InRad) *
                       Math.Pow(Math.Sin(dLongitude / 2.0), 2.0);

            // Intermediate result c (great circle distance in Radians).
            double c = 2.0 * Math.Asin(Math.Sqrt(a));

            // Distance.
            // const Double kEarthRadiusMiles = 3956.0;
            const Double kEarthRadiusKms = 6376.5;
            dDistance = kEarthRadiusKms * c;

            return dDistance;
        }

        internal void RefreshSegmentEfforts(int segmentId)
        {
            SegmentPlacingChangesList = new List<string>();
            wcSegmentEffortsArr.Add(segmentId);
            wcSegmentMyEffortsArr.Add(segmentId);
            GetNextSegmentEfforts();
        }

        internal void SegmentExplorer(System.Device.Location.GeoCoordinate BottomRight, System.Device.Location.GeoCoordinate TopLeft)
        {
            LoadType = "SegmentExplorer";
            //SegmentExplorerItemsRemaining = 2;
            ExplorerSegments = new ObservableCollection<Segment>();

            if (!wcSegmentExplorer.IsBusy)
            {
                //SegmentExplorerList = new List<int>();
                Uri uri = new Uri("http://" + ServiceLocation + "/v3/segments/search?bounds=" + BottomRight.Latitude.ToString() + "," + TopLeft.Longitude.ToString() + "," + TopLeft.Latitude.ToString() + "," + BottomRight.Longitude.ToString() + "&zoom=15&min_cat=0&max_cat=1&activity_type=cycling");
                wcSegmentExplorer.OpenReadAsync(uri);
            }
            //http://app.strava.com/api/v3/segments/search?bounds=53.309979,-1.618571,53.325617,-1.579433&zoom=15&min_cat=0&max_cat=1&activity_type=cycling
        }

        Collection<Double> decodePolyline(string polyline)
        {
            if (polyline == null || polyline == "") return null;

            char[] polylinechars = polyline.ToCharArray();
            int index = 0;
            Collection<Double> points = new Collection<Double>();
            int currentLat = 0;
            int currentLng = 0;
            int next5bits;
            int sum;
            int shifter;

            while (index < polylinechars.Length)
            {
                // calculate next latitude
                sum = 0;
                shifter = 0;
                do
                {
                    next5bits = (int)polylinechars[index++] - 63;
                    sum |= (next5bits & 31) << shifter;
                    shifter += 5;
                } while (next5bits >= 32 && index < polylinechars.Length);

                if (index >= polylinechars.Length)
                    break;

                currentLat += (sum & 1) == 1 ? ~(sum >> 1) : (sum >> 1);

                //calculate next longitude
                sum = 0;
                shifter = 0;
                do
                {
                    next5bits = (int)polylinechars[index++] - 63;
                    sum |= (next5bits & 31) << shifter;
                    shifter += 5;
                } while (next5bits >= 32 && index < polylinechars.Length);

                if (index >= polylinechars.Length && next5bits >= 32)
                    break;

                currentLng += (sum & 1) == 1 ? ~(sum >> 1) : (sum >> 1);

                points.Add(Convert.ToDouble(currentLat) / 100000.0);
                points.Add(Convert.ToDouble(currentLng) / 100000.0);
            }

            return points;
        }
    }
}